import Player from "./Player";
import NetUtil from "./util/NetUtil";
import StepManager from "./StepManager";
import Command from "./Command";
import ACTION_STATE from "./Direction";
import Color = cc.Color;

const { ccclass, property } = cc._decorator;

@ccclass
export default class Game extends cc.Component {
  private players: Player[] = [];
  @property(cc.Prefab) private playerPrefab: cc.Prefab = null;
  @property(cc.Component) private stepManager: StepManager = null;
  @property(cc.Node) private layoutNode: cc.Node = null;
  @property(cc.EditBox) private nameEdit: cc.EditBox = null;
  @property(cc.Node) private startNode: cc.Node = null;
  @property(cc.Node) private reconnectNode: cc.Node = null;
  @property(cc.Label) private hintLabel: cc.Label = null;
  @property(cc.Node) private controlNode: cc.Node = null;
  @property(cc.Node) private controlGanNode: cc.Node = null;
  @property(cc.TiledMap) private map: cc.TiledMap = null;
  @property(cc.ScrollView) private playersList: cc.ScrollView = null;
  private myName: string = null;
  private isStart: boolean = false;
  private angle: number = 0;
  private playerState: number = ACTION_STATE.STOP;
  private controlCenterVec = null;
  private playerCount :number = 0;

  public onLoad() {
    this.controlCenterVec = new cc.Vec2(this.controlNode.width / 2, this.controlNode.height / 2);
    this.listenEvent();
  }

  cmdUpdate() {
    // 发指令
    let player = this.getMySelf();
    let command: Command = { playerState: this.playerState, stepTime: this.stepManager.stepTime, angle: this.angle, skillActive: player.inSkillActive };
    let route: string = "game.gameHandler.message";
    let msg: any = { command: command };
    NetUtil.notify(route, msg);
    // cc.log("cmd to server="+msg);
  }

  mapUpdate() {
    let self = this.getMySelf();
    if (!self) {
      return;
    }
    for (let player of this.players) {
      player.node.x = player.x;
      player.node.y = player.y;
    }
    this.map.node.x = -self.x;
    this.map.node.y = -self.y;
  }

  public onDestory() {
    this.removeEvent();
  }

  addEventListener() {
    let touchPos = cc.v2(0, 0);
    this.node.on(
      cc.Node.EventType.TOUCH_START,
      (event: cc.Event.EventTouch) => {
        touchPos = event.getLocation();
      },
      this
    );

    this.node.on(
      cc.Node.EventType.TOUCH_MOVE,
      (event: cc.Event.EventTouch) => {
        this.controlMoveCallBack(event);
      },
      this
    );

    this.node.on(
      cc.Node.EventType.TOUCH_END,
      (event: cc.Event.EventTouch) => {
        this.onKeyUp();
        this.controlEndCallBack();
      },
      this
    );
  }

  onAttack() {
    let player = this.getMySelf();
    if (player.inSkillActive != -1) {
      return;
    }
    player.inSkillActive = 0;
    cc.log("attack action success");
  }

  /**
   * 控制按钮
   */
  controlMoveCallBack(event) {
    let touches = event.getTouches();
    let touchLoc = touches[0].getLocation();
    let touchPoint: cc.Vec2 = this.controlNode.convertToNodeSpace(touchLoc);
    // 设置控制点 限制超出父节点
    let subVec = touchPoint.sub(this.controlCenterVec);
    let dis = subVec.mag();
    if (dis > this.controlNode.width / 2) {
      let nv = subVec.normalizeSelf();
      this.controlGanNode.x = this.controlCenterVec.x + (nv.x * this.controlNode.width) / 2;
      this.controlGanNode.y = this.controlCenterVec.y + (nv.y * this.controlNode.width) / 2;
    } else {
      this.controlGanNode.setPosition(touchPoint);
    }
    this.angle = Math.atan2(touchPoint.y - this.controlCenterVec.y, touchPoint.x - this.controlCenterVec.x);
    this.playerState = ACTION_STATE.MOVE;
  }

  /**
   * 松开时回复控制点到中点
   */
  controlEndCallBack() {
    // 恢复控制点位置控制点
    this.controlGanNode.setPosition(this.controlCenterVec);
    // let player = this.getMySelf();
    // if (player && player.inSkillActive !== 0) {
    //   player.inSkillActive = -1;
    // }
  }

  private listenEvent() {
    this.addEventListener();
    // cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
    // cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
    this.startNode.on("click", this.onClickStart, this);
    this.reconnectNode.on("click", this.onClickReconnect, this);
  }

  private removeEvent() {
    // cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
    this.startNode.off("click", this.onClickStart, this);
    this.reconnectNode.off("click", this.onClickReconnect, this);
  }

  private onKeyUp() {
    this.angle = 0;
    this.playerState = ACTION_STATE.STOP;
  }

  private onClickStart(event: cc.Event.EventCustom) {
    if (NetUtil.connected) {
      this.ready();
    } else {
      NetUtil.init(this.ready.bind(this));
    }
  }

  private onClickReconnect(event: cc.Event.EventCustom) {
    if (!this.isStart) return;

    let route: string = "game.gameHandler.getHistoryCommands";
    let msg: any = {};
    NetUtil.request(route, msg, (data: any) => {
      this.stepManager.reconnect(data.historyCommands);
    });
  }

  private onStart(data: any) {
    cc.log("data=",data);
    this.isStart = true;
    // 设置玩家名
    this.playersList.content.removeAllChildren(true);
    for (let i = 0; i < data.playerList.length; i++) {
      let isEnemy: boolean = this.myName !== data.playerList[i];
      this.addPlayer(data.playerList[i],isEnemy);
      this.onAddPlayerName("玩家" + (i + 1) + ":" + data.playerList[i]);
    }
    // 显示提示
    this.hintLabel.string = "开始游戏";
    this.hintLabel.node.opacity = 255;
    let fadeOutAction: cc.Action = cc.fadeOut(3.0);
    this.hintLabel.node.runAction(fadeOutAction);
    // 开始收帧
    this.stepManager.startGame(data.stepInterval,this.myName,this.players);
    this.onKeyUp();
    this.controlEndCallBack();
    setInterval(this.cmdUpdate.bind(this), 20); //1000 / 20
    setInterval(this.mapUpdate.bind(this), 1000 / 60); //1000 / 20
  }

  //获取自己
  getMySelf(): Player {
    for (let i = 0; i < this.players.length; i++) {
      let bSelf: boolean = this.players[i].bSelf;
      if (bSelf) {
        return this.players[i];
      }
    }
  }

  private onPlayerExit(data: any) {
    this.isStart = false;
    // 显示布局
    this.layoutNode.active = true;
    // 显示提示
    this.hintLabel.string = "游戏结束";
    this.hintLabel.node.opacity = 255;
    // 停止收帧
    this.stepManager.stopGame();
    // 初始化
    this.players.forEach((player: Player) => {
      player.init();
    });
  }

  private ready() {
    this.myName = this.nameEdit.string;
    // 隐藏布局
    this.layoutNode.active = false;
    // 显示提示
    this.hintLabel.string = "等待中……";
    this.hintLabel.node.opacity = 255;
    this.onAddPlayerName("玩家1:" + this.myName);
    // 发送请求
    NetUtil.once("onStart", this.onStart, this);
    NetUtil.once("onPlayerExit", this.onPlayerExit, this);
    let route: string = "connector.entryHandler.ready";
    let msg: any = { uid: this.myName };
    NetUtil.notify(route, msg);
  }

  onAddPlayerName(name: string) {
    let node = new cc.Node();
    let text = node.addComponent(cc.Label);
    text.fontSize = 20;
    text.node.anchorX = 0;
    text.node.anchorY = 0.5;
    text.node.color = Color.GREEN;
    text.string = name;
    text.lineHeight = 22;
    node.x = -this.playersList.content.width / 2;
    this.playersList.content.addChild(node);
  }

  addPlayer(name,isEnemy:boolean){
    let node = this.instantiate(this.playerPrefab,this.map.node);
    let player = node.getComponent(Player);
    player.angle = 0;
    player.setPlayerName(name, isEnemy);
    this.playerCount++;
    node.setPosition(cc.v2(0,0);
    this.players.push(player);
  }

  instantiate(prefab: cc.Prefab, target?: cc.Node, zOrder?: number, defaultActive = true): cc.Node {
    if (prefab) {
      let nodePrefab = cc.instantiate(prefab);
      if (nodePrefab) {
        nodePrefab.active = defaultActive;
      } else {
        cc.error("instantiate 实例化失败", prefab);
      }
      if (target && target["_children"]) {
        target.addChild(nodePrefab, zOrder);
      }
      return nodePrefab;
    } else {
      cc.error("instantiate prefab为空", prefab);
      return null;
    }
  }
}
